import { TextModel, SelectionModel, SelectionType } from "./models";
import { SourceView, ViewProvider } from "./view";
import { myKeyboardEvent, SelectionEvent } from "./event";
import { Operation, SetSelectionOperation, RemoveTextOperation, InsertTextOperation } from "./operations";
import { ViewModels } from "./constants/view_model";

class Editor {
  container: HTMLElement;
  keyboardEventHandler: myKeyboardEvent | null = null;
  mouseEventHandler: SelectionEvent | null = null;

  private _textModel: TextModel | null = null;
  private _selectionModel: SelectionModel | null = null;
  private _viewProvider: ViewProvider;
  private _view: SourceView | null = null;

  constructor(container: HTMLElement) {
    this.container = container;
    this._viewProvider = new ViewProvider();
  }
  
  init() : void {
    this.keyboardEventHandler = new myKeyboardEvent(this, this.container);
    this.mouseEventHandler = new SelectionEvent(this, this.container);
    this.keyboardEventHandler.addListeners();
    this.mouseEventHandler.addListeners();

    this._textModel = new TextModel();
    this._selectionModel = new SelectionModel();
    this._view = this._viewProvider.provide(ViewModels.division, this._textModel, this._selectionModel, this.container);
  }

  getTextModel() : TextModel | null {
    return this._textModel;
  }

  getSelectionModel() : SelectionModel | null {
    return this._selectionModel;
  }

  apply(operation: Operation) : void {
    operation.apply(this);
  }

  insertTextAtCursor(text: string) : void {
    if (this._selectionModel == null) return;
    const selection: SelectionType | null = this._selectionModel.getSelection();
    if (selection == null) return;

    if (!this._selectionModel.isCollapse()) {
      const removeTextOperation: RemoveTextOperation = new RemoveTextOperation(selection.anchor, selection.focus);
      this.apply(removeTextOperation);
    }

    let startIndex: number = this._selectionModel.isBackward() ? selection.focus : selection.anchor;
    let cursorIndex: number = startIndex + text.length;
    const insertTextOperation: InsertTextOperation = new InsertTextOperation(text, startIndex);
    this.apply(insertTextOperation);
    this.setSelection(cursorIndex, cursorIndex);
  }

  removeTextAtCursor() : void {
    if (this._selectionModel == null) return;
    const selection: SelectionType | null = this._selectionModel.getSelection();
    if (selection == null) return;

    let startIndex: number = this._selectionModel.isBackward() ? selection.focus : selection.anchor;
    let endIndex: number = this._selectionModel.isBackward() ? selection.anchor : selection.focus;
    if (this._selectionModel.isCollapse()) {
      startIndex = Math.max(startIndex - 1, 0);
    }

    const removeTextOperation: RemoveTextOperation = new RemoveTextOperation(startIndex, endIndex);
    this.apply(removeTextOperation);
    this.setSelection(startIndex, startIndex);
  }

  setSelection(anchor: number, focus: number) : void {
    const selection: SelectionType | null = this._selectionModel?.getSelection() || null;
    let curAnchor = selection?.anchor;
    let curFocus = selection?.anchor;
    if (anchor !== curAnchor || focus !== curFocus) {
      const selectionOperaction: SetSelectionOperation = new SetSelectionOperation({ anchor, focus });
      this.apply(selectionOperaction);
    }
  }

  // 撤销
  undo() {}

  // 回退
  redo() {}
}

export default Editor;